package tester;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import src.Bond;
import src.BondsBruteForce;
import src.ClosureType;
import src.Context;

public class BondTester {

    private static List<int[]> allVariations = new ArrayList<int[]>();
	
	public static void main(String[] args) {
		Double[][] relation1 = {{ 0.0, 1.0, 0.5, 0.5, 0.5 },			
			 					{ 0.0, 0.5, 0.5, 1.0, 1.0 }};
		Context c1 = new Context(3, relation1);
		
		Double[][] relation2 = {{ 1.0, 1.0, 0.5, 1.0 },			
								{ 1.0, 1.0, 1.0, 0.5 },
								{ 1.0, 0.5, 0.0, 1.0 }};
		Context c2 = new Context(3, relation2);
		
		c1.lattice(ClosureType.UP_DOWN);		
		c2.lattice(ClosureType.UP_DOWN);
	
		System.out.println("C1 objects count: " + "\t" + c1.getObjectsCount());
		System.out.println("C1 attributes count: " + "\t" + c1.getAttributesCount());
		System.out.println("C2 objects count: " + "\t" + c2.getObjectsCount());
		System.out.println("C2 attributes count: " + "\t" + c2.getAttributesCount());
		System.out.println();
		
//		-------------EXTENTS--------------------
		
		System.out.println("c1 - extents");
		System.out.println();
		for (int i = 0; i < c1.getExtents().size(); i++) {
			System.out.println(i + ": " + c1.getExtents().get(i));
		}	
		System.out.println();
		
		List<List<List<Double>>> extentVariations = allVariations(c1.getExtents(), c2.getAttributesCount());
		
		System.out.println("all variations");
		System.out.println();
		for (int i = 0; i < allVariations.size(); i++) {
			System.out.println((i + 1) + ": " + Arrays.toString(allVariations.get(i)));
		}
		System.out.println();
		
		System.out.println("all extent variations");
		System.out.println();
		for (int i = 0; i < extentVariations.size(); i++) {
			System.out.println((i + 1) + ": " + extentVariations.get(i));
		}
		System.out.println();
		
//		-------------INTENTS--------------------
		
		System.out.println("c2 - intents");
		System.out.println();
		for (int i = 0; i < c2.getIntents().size(); i++) {
			System.out.println(i + ": " + c2.getIntents().get(i));
		}	
		System.out.println();
		
		List<List<List<Double>>> intentVariations = allVariations(c2.getIntents(), c1.getObjectsCount());

		System.out.println("all variations");
		System.out.println();
		for (int i = 0; i < allVariations.size(); i++) {
			System.out.println((i + 1) + ": " + Arrays.toString(allVariations.get(i)));
		}
		System.out.println();
		
		System.out.println("all intent variations");
		System.out.println();
		for (int i = 0; i < intentVariations.size(); i++) {
			System.out.println((i + 1) + ": " + intentVariations.get(i));
		}
		System.out.println();
		
		System.out.println("BONDs");
		System.out.println();
		int i = 0;
		System.out.println("bonds from extent variations");
		System.out.println();
		for (List<List<Double>> variation : extentVariations) {
			List<List<Double>> transposedVariation = transpose(variation);
			if (intentVariations.contains(transposedVariation)) {
				System.out.println(++i + ": " + variation + "  -->  " + transposedVariation);
			}
		}	
		System.out.println();
		
		i = 0;
		System.out.println("bonds from intent variations");
		System.out.println();		
		for (List<List<Double>> variation : intentVariations) {
			List<List<Double>> transposedVariation = transpose(variation);
			if (extentVariations.contains(transposedVariation)) {
				System.out.println(++i + ": " + transposedVariation + "  -->  " + variation);
			}
		}	
		System.out.println();
		
		System.out.println("------------using Bonds class-----------------");
		BondsBruteForce b = new BondsBruteForce(relation1, relation2, ClosureType.UP_DOWN, 3);

		System.out.println("BONDs");
		System.out.println();		
		
		System.out.println("bonds from extent variations");
		System.out.println();
		
		i = 0;
		for (Bond bond : b.getBondsFromExtentPointOfView()) {
			System.out.println(++i + ": " + bond);
		}
		System.out.println();
		
		System.out.println("bonds from intent variations");
		System.out.println();	
		
		i = 0;
		for (Bond bond : b.getBondsFromIntentPointOfView()) {
			System.out.println(++i + ": " + bond);
		}
		System.out.println();
	}
	
	private static List<List<List<Double>>> allVariations(List<List<Double>> sets, int k) {
		allVariations.clear();
//		input is list of extents or intents (fuzzy sets)		
//		generate all variations with repetition
		List<List<List<Double>>> result = new ArrayList<List<List<Double>>>();
		
		int[] array = new int[k];		
		generateVariations(0, array, sets.size());
	
		for (int i = 0; i < allVariations.size(); i++) {
			int[] integerVariation = allVariations.get(i);	
			List<List<Double>> variation = new ArrayList<List<Double>>();
			for (int j = 0; j < integerVariation.length; j++) {
//				we generate indexes starting with 1, that's why -1
				List<Double> set = sets.get(integerVariation[j] - 1);	
				variation.add(set);
			}
			result.add(variation);
		}
		
		return result;		
	}

    private static void generateVariations(int fromIndex, int[] array, int n) {
        if (fromIndex == array.length) {
        	allVariations.add(array.clone());
            return;
        }

    	for (int i = 1; i <= n; i++) {
    		array[fromIndex] = i;
    		generateVariations(fromIndex + 1, array, n);                    
        }
    }
    
    private static List<List<Double>> transpose(List<List<Double>> fuzzySets) {
    	List<List<Double>> result = new ArrayList<List<Double>>();
    	
    	for (int i = 0; i < fuzzySets.get(0).size(); i++) {
    		List<Double> temp = new ArrayList<Double>();
    		for (int j = 0; j < fuzzySets.size(); j++) {
    			temp.add(fuzzySets.get(j).get(i));
			}
    		result.add(temp);
		}

    	return result;
    }
}
